fix(hooks): stop SessionEnd from mutating tracked STATE.md#17
Merged
Conversation
The SessionEnd hook overwrote STATE.md's `last_updated` frontmatter on every session end via `sed -i`. STATE.md is a tracked source-of-truth Markdown, written deliberately by skills (init-project, plan-milestone, plan-task, summarize-task, reassess-roadmap, plan-ceo-review) as part of state transitions. A hook firing on every session-end has no business writing to it -- the result was a phantom diff in `git status` after every session, in every ytstack project. The same hook already appends to `journal/sessions.jsonl` (gitignored, append-only), which carries the recency information without polluting the tracked tree. SessionStart's "Last updated:" line now reflects the last deliberate skill-driven state transition rather than the last process exit -- which is the more useful semantic anyway. Smoke-tested: STATE.md sha unchanged before/after hook invocation; journal entry written correctly with milestone/slice/task/session_id. Surfaced from a downstream user whose engine-vault setup clones a repo containing `.ytstack/` into a subdirectory: every Claude Code session in the vault was rewriting the engine's dev-tracking STATE.md.
Required for `/plugin update` to pick up the SessionEnd fix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The SessionEnd hook overwrote
STATE.md'slast_updatedfrontmatter on every session end viased -i.STATE.mdis a tracked source-of-truth Markdown, written deliberately by skills (init-project,plan-milestone,plan-task,summarize-task,reassess-roadmap,plan-ceo-review) as part of state transitions. A hook firing on every session-end has no business writing to it -- the result was a phantom diff ingit statusafter every session, in every ytstack project.The same hook already appends to
journal/sessions.jsonl(gitignored, append-only), which carries the recency information without polluting the tracked tree.Behavior change
SessionStart's "Last updated: X" line now reflects the last deliberate skill-driven state transition rather than the last process exit. That's the more useful semantic anyway -- "when was real work last done on this project" beats "when did Claude Code last close a tab".Breakage audit
Searched the repo for references to
last_updatedoutside the worktree mirrors:Readers (1):
hooks/session-start:110-- reads field for the "Last updated: X" line in injected context. Display only; no logic branches on the value.Writers (kept, intentional):
skills/init-project/SKILL.md-- seeds the fieldskills/plan-milestone/SKILL.md,plan-task,summarize-task,reassess-roadmap,plan-ceo-review-- bump on state transitionsWriter removed (this PR):
hooks/session-end-- the unsolicited mutationNo tests reference
session-endorlast_updated(grepacross.sh/.bats/.pyexcluding vendor). Agent Teams orchestration hooks (post-tool-use-bash,task-completed,task-created,teammate-idle) don't touch the field.Smoke test
Reporter context
Surfaced from a downstream user whose engine-vault setup clones a repo containing
.ytstack/into a subdirectory: every Claude Code session in the vault was rewriting the engine's dev-trackingSTATE.md. The leak (engine.ytstack/in vault distributions) is a separate concern in the downstream repo; this PR fixes the upstream side that makes the leak visible (the unsolicited write).Test plan
last_updatedbeing currentgit statusis clean after session-end🤖 Generated with Claude Code
Note
Low Risk
Low risk: removes an unsolicited
sedwrite to trackedSTATE.mdinhooks/session-end, reducing noisy diffs; behavior change is limited to thelast_updatedfield no longer updating on session exit.Overview
Prevents
hooks/session-endfrom updatingSTATE.md’slast_updatedon every session end; it now only appends asession-endentry tojournal/sessions.jsonland clarifies this contract in comments.Bumps plugin metadata version from
0.1.3to0.1.4in.claude-plugin/plugin.jsonand.claude-plugin/marketplace.json.Reviewed by Cursor Bugbot for commit cc2b5d8. Bugbot is set up for automated code reviews on this repo. Configure here.